#pragma once
#include "execution_defs.h"
#include "execution_manager.h"
#include "executor_abstract.h"
#include "index/ix.h"
#include "system/sm.h"

class InsertExecutor : public AbstractExecutor {
   private:
    TabMeta tab_;
    std::vector<Value> values_;
    RmFileHandle *fh_;
    std::string tab_name_;
    Rid rid_;
    SmManager *sm_manager_;

   public:
    InsertExecutor(SmManager *sm_manager, const std::string &tab_name, std::vector<Value> values, Context *context) {
        sm_manager_ = sm_manager;
        tab_ = sm_manager_->db_.get_table(tab_name);
        values_ = values;
        tab_name_ = tab_name;
        if (values.size() != tab_.cols.size()) {
            throw InvalidValueCountError();
        }
        // Get record file handle
        fh_ = sm_manager_->fhs_.at(tab_name).get();
        context_ = context;
    };

    std::unique_ptr<RmRecord> Next() override {
        // 通过创建记录缓冲区、将记录插入记录文件以及将记录插入索引来完成插入操作。
        // lab3 task3 Todo
        // Make record buffer
        // Insert into record file
        // Insert into index
        // lab3 task3 Todo end
        
        // 创建记录缓冲区
        RmRecord rec(fh_->get_file_hdr().record_size);// 初始化一个记录对象，大小为文件头中指定的记录大小
        for (size_t i = 0; i < values_.size(); i++)// 遍历所有要插入的值
        {
            auto &col = tab_.cols[i];
            auto &val = values_[i];
            if (col.type != val.type)// 检查列类型是否与值类型匹配
            {
                throw IncompatibleTypeError(coltype2str(col.type), coltype2str(val.type));
            }
            val.init_raw(col.len);// 初始化值的原始数据
            memcpy(rec.data + col.offset, val.raw->data, col.len);// 将值复制到记录的相应位置
        }
        // 插入记录文件
        rid_ = fh_->insert_record(rec.data, context_);// 将记录插入记录文件，并获取记录标识符（RID）
        // 插入索引
        for (size_t i = 0; i < tab_.cols.size(); i++)
        {
            auto &col = tab_.cols[i];
            if (col.index)// 对于每个有索引的列
            {
                auto ih = sm_manager_->ihs_.at(sm_manager_->get_ix_manager()->get_index_name(tab_name_, i)).get();// 获取索引句柄
                ih->insert_entry(rec.data + col.offset, rid_,context_->txn_);// 将记录的相应部分插入索引
            }
        }
        return std::make_unique<RmRecord>(rec);// 返回插入的记录
    }
    Rid &rid() override { return rid_; }
};